package com.gin.kotlin.vegetables_kot.base

import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Message
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.activity.result.ActivityResult
import androidx.activity.result.ActivityResultCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.DrawableRes
import androidx.appcompat.content.res.AppCompatResources
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewbinding.ViewBinding
import androidx.viewpager2.widget.ViewPager2
import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import com.gin.kotlin.vegetables_kot.app.App

import com.gin.kotlin.vegetables_kot.base.AbstractBindingActivity
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator

abstract class AbstractBindingFragment<T : ViewBinding> : Fragment(), ViewBindProvider<T>, Handler.Callback, HandlerHolder {
    protected val TAG = this::class.java.simpleName

    /**
     * Binding对象
     */
    var b: T? = null

    /**
     * handler
     */
    override var handler: MyHandler? = null


    /**
     * 根据drawable Id 获取 Drawable
     */
    fun getDrawable(@DrawableRes drawableId: Int): Drawable? {
        return AppCompatResources.getDrawable(requireContext(), drawableId)
    }

    /**
     * 获取上级结构的Handler
     * @return MyHandler
     */
    fun findParentHandler(): MyHandler {
        val h1 = (parentFragment as? AbstractBindingFragment<*>)?.handler
        if (h1 != null) return h1

        val h2 = (requireActivity() as? AbstractBindingActivity<*>)?.handler
        if (h2 != null) return h2
        return App.INSTANCE.handler!!
    }

    /**
     * 注册一个活动启动器，用于在需要活动返回处理结果时
     * @param callback 回调，建议使用this
     * @return ActivityResultLauncher<Intent>
     */
    fun registerLauncher(callback: ActivityResultCallback<ActivityResult>) =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult(), callback)


    /**
     * 获取当前fragment中的指定位置的子fragment
     *
     * @param position 位置
     * @return Fragment
     */
    fun findCurrentFragment(position: Int) = childFragmentManager.findFragmentByTag("f$position")

    /**
     * 生命周期 onCreateView
     */
    final override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        this.b = instanceViewBinding(inflater, container)
        // 处理参数
        this.handler = MyHandler(requireContext(), this)

        arguments?.also { handleArguments(it) }
        onCreateView()
        return this.b?.root
    }

    override fun onDestroyView() {
        super.onDestroyView()
        this.handler?.onDestroy()
        this.handler = null
        this.b = null
    }

    /**
     * 实例化 ViewBinding 对象, 使用对应模板的Binding类的inflate方法进行构造
     * @param inflater 渲染器
     * @param container 容器(Fragment用)
     * @return T
     */
    override fun instanceViewBinding(inflater: LayoutInflater, container: ViewGroup?): T? {
        val parameterizedType =
            AbstractBindingActivity.findParameterizedType(this.javaClass)
                ?: throw RuntimeException("ViewBinding创建失败: ${this.javaClass.simpleName}, 泛型未找到")
        for (type in parameterizedType.actualTypeArguments) {
            if (type is Class<*>) {
                try {
                    val method = type.getMethod("inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.javaPrimitiveType)
                    @Suppress("UNCHECKED_CAST")
                    return method.invoke(type, inflater, container, false) as T
                } catch (e: NoSuchMethodException) {
                    Log.d(TAG, "instanceViewBinding: 方法未找到")
                }
            }
        }
        return null
    }


    /**
     * 处理消息
     */
    override fun handleMessage(msg: Message): Boolean {
        Log.d(TAG, "handleMessage: 向父级抛出消息: ${msg.what}")
        val handler = findParentHandler()
        handler.sendMessage(handler.obtainMessage(msg.what, msg.arg1, msg.arg2, msg.obj))
        return true
    }

    /**
     * onCreateView的后续操作 ，如通过  [FragmentActivity.addMenuProvider] 添加菜单
     */
    abstract fun onCreateView()

    /**
     * 处理参数
     * @param bundle Bundle
     */
    open fun handleArguments(bundle: Bundle) {}

    /**
     * 从bundle中获取数据
     * @param bundle Bundle
     * @param key String
     * @param kClass Class<T>
     * @return T
     */
    fun <T : Any> parseBundle(bundle: Bundle, key: String, kClass: Class<T>): T =
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            bundle.getParcelable(key, kClass)
        } else {
            bundle.getParcelable(key)
        }?.also {
            Log.i(this::class.java.simpleName, "获得数据: ${mapper.writeValueAsString(it)}")
        } ?: throw RuntimeException("必须提供数据")

    /**
     * 关联一个 TabLayout 和 ViewPager2
     * @param tabLayout TabLayout
     * @param viewPager2 ViewPager2
     * @param strategy TabConfigurationStrategy
     * @return TabLayoutMediator
     */
    fun attachTabLayout(tabLayout: TabLayout, viewPager2: ViewPager2, strategy: TabLayoutMediator.TabConfigurationStrategy) =
        TabLayoutMediator(tabLayout, viewPager2, true, strategy).also { it.attach() }


    companion object {
        val mapper: ObjectMapper = ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL).registerModule(JavaTimeModule())
    }
}